home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / pgp20src.zip / RANDOM.C < prev    next >
C/C++ Source or Header  |  1992-09-03  |  25KB  |  713 lines

  1. /**********************************************************************
  2.     random.c - C source code for random number generation - 19 Nov 86
  3.     (c) Copyright 1986 by Philip Zimmermann.  All rights reserved.  
  4.  
  5.     Revised Jul 88 by PRZ and again Dec 88 by Allan Hoeltje
  6.         to use IBM PC 8253 timer0 for a faster counter.
  7.     Revised Apr 89 by PRZ to recycle random bytes.
  8.     Revised 29 Jul 91 by PRZ for use in more limited environments.
  9.     Later revised by several other folks to run in difficult environments
  10.     such as Unix, VAX/VMS and others.
  11.     Revised 2 Sep 92 by Peter Gutmann and PRZ to use MD5 to distill 
  12.     high quality randomness down from low-grade random noise.
  13.  
  14.     This code generates truly random numbers derived from a counter that is 
  15.     incremented continuously while the keyboard is scanned for user input.
  16.     Every time the user touches a key, the least significant bits of the 
  17.     counter are pushed on a stack.  Later, this supply of random bytes can
  18.     be popped off the stack by applications requiring stochastic numbers.
  19.     Cryptographic applications require this kind of randomness.
  20.  
  21.     The only requirement to make this work is that keypress must be called 
  22.     frequently, and/or getkey must be called to read the keyboard.  
  23.  
  24.     Note that you can only get as many random bytes as the number of
  25.     bytes accumulated by the user touching the keyboard.
  26. **********************************************************************/
  27.  
  28. #include     <string.h>
  29. #include     <time.h>
  30. #include    "random.h"
  31. #include    "language.h"
  32.  
  33. /*    pseudorand() is used mainly for debugging while porting to a new
  34.     machine-- it makes reproducible sequences, which makes debugging
  35.     easier.  To use it as the source of random numbers, define
  36.     PSEUDORANDOM.  Warning:  Don't do this for actual applications.
  37. */
  38. static int randseed=0; /* used only by pseudorand() function. */
  39. int pseudorand(void)
  40. /*    Home-grown 16-bit LCG pseudorandom generator. */
  41. {    randseed = (randseed*31421 + 6927) & 0xffff;
  42.     return (randseed);
  43. }    /* pseudorand */
  44.  
  45.  
  46. #ifndef PSEUDORANDOM        /* use truly random numbers */
  47.  
  48. /* #define USEPCTIMER */ /* use fast hardware timer on IBM PC or AT or clone */
  49. /* #define DEBUG */
  50.  
  51. /*    If operating system shields keyboard event timings from user, then 
  52.     we can't use any hardware or software timer logic to time events.
  53.     This is a messy situation, so we have special logic to handle
  54.     it, defining the symbol CRUDE to compile special code. 
  55.     This may be needed in multiuser Unix systems, for example.
  56. */
  57. #ifdef CRUDE /* No environmental support to capture keyboard event times */
  58. #undef USEPCTIMER
  59. #endif    /* CRUDE */
  60.  
  61. #include    <stdio.h>    /* for putchar() and printf() */
  62. #include     <time.h>
  63.  
  64. /* Prototypes for kbhit() (whether the keyboard has been hit) and getch()
  65.    (like getchar() but no echo, no buffering).  Not available under some
  66.    implementations */
  67.  
  68. int kbhit( void );
  69. int getch( void );
  70.  
  71. #ifdef DEBUG
  72. #define DEBUGprintf1(x) fprintf(stderr,x)
  73. #define DEBUGprintf2(x,y) fprintf(stderr,x,y)
  74. #else
  75. #define DEBUGprintf1(x)
  76. #define DEBUGprintf2(x,y)
  77. #endif
  78.  
  79.  
  80. int randcount = 0 ;        /* # of random bytes accumulated in pool */
  81. static byte randpool[256] = {0} ;    /* pool of truly random bytes */
  82. static int recyclecount = 0 ;    /* # of recycled random bytes accumulated */
  83. static byte recyclepool[256] = {0} ; /* pool of recycled random bytes */
  84. static int recycleptr = 0;    /* points to next byte to grab in recyclepool */
  85.  
  86. /* fastcounter is a free-running counter incremented in main event loop. */
  87. static unsigned fastcounter = 0;    /* not needed if we can use the PC timer. */
  88. static unsigned lastcounter = 0;
  89. static char toofast = 0;
  90. /* toofast indicates keystroke rejected because it was typed too fast */
  91.  
  92. #ifdef CRUDE 
  93. static boolean capturemode = FALSE;
  94. #endif    /* CRUDE */
  95.  
  96. #ifdef AMIGA
  97. int aecho;
  98. #endif
  99.  
  100. /* Information needed by the MD5 code for distilling large quantities of
  101.    semi-random information into a small amount of highly-random information.
  102.    This works as follows:
  103.  
  104.    Initially we have no random information.  Whenever we add more slightly
  105.    random data, we put it in the MD5 data field and run MD5 over the
  106.    random byte pool.  This propagates the randomness in the data evenly
  107.    throughout the pool due to the avalanche effect of the MD5 transformation.
  108.    The randomness transformation is carried out inside capturecounter() when
  109.    the data is entered, and is transparent to the operation of the rest of
  110.    the code.
  111.  
  112.    The use of this randomness-distillation can be turned off by toggling the
  113.    following define in case the randomness code needs to be run on a
  114.    washing-machine controller or somesuch.
  115. */
  116.  
  117. #define USE_MD5        /* Turn on MD5 randomization */
  118.  
  119. #ifdef USE_MD5
  120. void Transform( unsigned long *seedBuffer, unsigned long *data );
  121. byte seedBuffer[ 64 ];            /* Buffer for MD5 seed value */
  122. boolean isInitialised = FALSE;    /* Whether buffer has been inited */
  123. byte iv[ 16 ];                    /* IV for MD5 transformation */
  124. #endif    /* USE_MD5 */
  125.  
  126. #ifdef USEPCTIMER    /* we will use fast hardware timer on IBM PC */
  127. /* #include <conio.h> */    /* function definitions for inp() and outp() */
  128. /* outp() and inp() works only for Microsoft C for IBM PC or AT */
  129. /* timer0 on 8253-5 on IBM PC or AT tics every .84 usec. */
  130. #define timer0        0x40    /* 8253 timer 0 port */
  131. #define timercntl    0x43    /* 8253 control register */
  132. #define timer0rwl    0x00    /* read lo/hi bytes of cntr 2 with latch */
  133. #define timer0rnl    0x30    /* read lo/hi bytes of cntr 2 w/o latch */
  134.  
  135. static byte latched_hitimer = 0; /* captured by keyboard ISR */
  136. static byte latched_lotimer = 0; /* captured by keyboard ISR */
  137. /* when kbisr captures timer, timer_latched is set. */
  138. static boolean timer_latched = FALSE;
  139.  
  140. static void kbisr(void)    /* Keyboard Interrupt Service Routine (ISR) */
  141. /*
  142.     kbisr should be called on the way into, or on the way out of,
  143.     or from within the DOS keyboard ISR, as long as it gets called
  144.     at the time of a keyboard interrupt.  Assumes that the real
  145.     DOS keyboard ISR captures the keystroke in the normal way.
  146.     Only the hardware timer counter is captured by the kbisr routine,
  147.     leaving the actual keystroke capture to the normal DOS keyboard ISR.
  148.     We indicate that a timer capture has taken place by setting 
  149.     timer_latched.
  150.  
  151.     NOTE: WE STILL NEED TO FIND A WAY to connect this subroutine with the 
  152.     normal keyboard ISR, so that kbisr gets called when there's a keyboard
  153.     interrupt.
  154. */
  155. {    outp(timercntl,timer0rwl);
  156.     latched_lotimer = inp(timer0);
  157.     latched_hitimer = inp(timer0);
  158.     timer_latched = TRUE;
  159. }    /* kbisr */
  160.  
  161. static unsigned short pctimer0(void)
  162. {
  163. /*    Reads and returns the hardware 8253 timer0 on the PC or AT
  164. **    or clone, shifted right 1 bit.
  165. **
  166. **    DO NOT SET THE HARDWARE COUNTER TO ZERO. It is already initialized
  167. **    by the system to be used by the clock.  It is set up in mode 3
  168. **    (square wave rate generator) and counts down by 2 from 0 (0xFFFF+1)
  169. **    to produce an 18.2 Hz square wave.  We may, however, READ the
  170. **    lo and hi bytes without causing any problems.  BUT just
  171. **    remember that the lo byte will always be even (since it is
  172. **    counting by two).
  173. **
  174. **    Note that we can not use counter 1 since it is tied to the
  175. **    dynamic RAM refresh hardware.  Counter 2 is tied to the 8255
  176. **    PPI chip to do things like sound.  Though it would be safe to
  177. **    use counter 2 it is not desirable since we would have to turn
  178. **    the speaker on in order to make the timer count!  Normally one
  179. **    sets counter 2 to mode 3 (square wave generator) to sound the
  180. **    speaker.  You can set mode 2 (pulse generator) and the speaker
  181. **    hardly makes any sound at all, a click when you turn it on and
  182. **    a click when you turn it off.  Counter 0 should be safe if
  183. **    we only read the counter bytes.
  184. **
  185. **    WARNING:  To use the hardware timer the way it really should be
  186. **    used, we ought to capture it via a keyboard interrupt service
  187. **    routine (ISR).    Otherwise, we may experience weaknesses in randomness
  188. **    due to harmonic relationships between the hardware counter frequency
  189. **    and the keyboard software polling frequency.  Unfortunately, this
  190. **    implementation does not currently use keyboard interrupts to
  191. **    capture the counter.  This is not a problem if we don't use the
  192. **    hardware counter, but instead use the software counter fastcounter.
  193. **    Thus, the hardware counter should not be used at all, unless we
  194. **    support it with an ISR.
  195. */
  196.     unsigned short t ;
  197.     /* See if timer has been latched by kbisr(). */
  198.     if (!timer_latched) /* The timer was not already latched. */
  199.         kbisr();    /* latch timer */
  200.     /* return latched timer and clear latch */
  201.     t = (     (((unsigned short) latched_hitimer) << 8) |
  202.          ((unsigned short) latched_lotimer)
  203.         ) >> 1 ;
  204.     timer_latched = FALSE;
  205.     return (t) ;
  206. }    /* pctimer0 */
  207.  
  208. #endif    /* ifdef USEPCTIMER */
  209.  
  210.  
  211. /* keybuf is used only by keypress(), getkey(), and capturecounter(). */
  212. static short keybuf = 0;
  213.  
  214.  
  215. #ifdef VMS
  216.  
  217. extern unsigned long    vms_clock_bits[2];    /* VMS Hardware Clock */
  218. extern const long    vms_ticks_per_update;    /* Clock update int. */
  219.  
  220. #endif /* VMS */
  221.  
  222. void capturecounter(void)
  223. /*    Push a fast counter on the random stack.  Should be called when
  224. **    the user touches a key or clicks the mouse.
  225. */
  226. {
  227.     int dt, i, j;
  228. #ifndef USE_MD5
  229.     static unsigned int accum = 0;
  230. #endif /* USE_MD5 */
  231.     static byte abits = 0;    /* number of accumulated bits in accum */
  232.     unsigned int accum1;
  233.  
  234. #define cbitsmask ((1 << cbits)-1)
  235.  
  236. #ifdef CRUDE /* No environmental support to capture keyboard event times. */
  237.     if (!capturemode)
  238.         return;    /* only captures during randaccum function */
  239. #endif    /* CRUDE */
  240.  
  241.     /*    fastcounter only contains timing information, in the form of a 
  242.         free-running timer, either hardware or software.
  243.         accum1 contains stuff from fastcounter and other sources,
  244.         like the actual key the user hit.
  245.     */
  246.  
  247. #if defined( USEPCTIMER    ) /* we will use fast hardware timer on IBM PC */
  248. #define cbits 8        /* number of bits of counter to capture each time */
  249.     fastcounter = pctimer0();    /* capture hardware timer */
  250. #elif defined( CRUDE )            /* no fast hardware timer available */
  251. #define cbits 2
  252. #else    /* not CRUDE */
  253. #define cbits 4        /* number of bits of counter to capture each time */
  254. #ifdef VMS
  255.     /* Capture fast system timer: */
  256.     SYS$GETTIM(&vms_clock_bits);
  257.     lib$ediv (&vms_ticks_per_update,
  258.         &vms_clock_bits,&vms_clock_bits,&vms_clock_bits[1]);
  259.     fastcounter = vms_clock_bits[1];
  260. #endif /* VMS */
  261. #endif    /* not USEPCTIMER */
  262.  
  263. #ifndef CRUDE    /* keyboard timings are available */
  264.     dt = fastcounter - lastcounter;
  265.     if (dt < 0)        /* timer rolled over past zero */
  266.         dt = -dt;    /* absolute value of time elapsed */
  267. #ifdef TEST_COUNTER
  268.     fprintf(stderr,"<dt=%6u>\n", dt);
  269. #endif
  270.     if ( ((unsigned) dt) < (unsigned)(1 << (cbits + 2)))
  271.     {
  272.         toofast++;    /* indicate a too-fast keystroke */
  273.         return;    /* only captures if enough time has passed */
  274.     }
  275. #endif /* not CRUDE */
  276.  
  277.     lastcounter = fastcounter;    /* latch timer info */
  278.  
  279. #ifdef USE_MD5
  280.     /* Initialise the MD5 info if necessary */
  281.     if( !isInitialised )
  282.     {    memset(seedBuffer, 0, 64);
  283.         memset(iv, 0, 16);
  284.         isInitialised = TRUE;
  285.     }
  286.  
  287.     /*    Add the slightly-random data to the MD5 input buffer.  Currently we
  288.         just add a few bytes of environmental noise, but we could mix in 
  289.         up to 512 bits worth.
  290.     */
  291.     seedBuffer[ 0 ] = keybuf;    /* actual character user typed */
  292.     seedBuffer[ 1 ] = lastcounter & 0xFF;
  293.     seedBuffer[ 2 ] = lastcounter >> 8;
  294.     accum1 = ( int ) clock();            /* clock ticks */
  295.     seedBuffer[ 3 ] = accum1 & 0xFF;
  296.     seedBuffer[ 4 ] = accum1 >> 8;
  297.     accum1 = ( int ) time(NULL);        /* seconds */
  298.     seedBuffer[ 5 ] = accum1 & 0xFF;
  299.     seedBuffer[ 6 ] = accum1 >> 8;
  300.     /* The preceding "noise quantum" has only cbits worth of randomness. */
  301.  
  302.     /* Now use MD5 to diffuse the randomness in these bits over the random
  303.        byte pool, raising the salinity of randomness in the pool.  The
  304.        transformation is carried out by "encrypting" the data in CFB mode
  305.        with MD5 as the block cipher */
  306.     for(i = 0; i < sizeof(randpool); i += 16)
  307.     {
  308.         Transform((unsigned long *) iv, (unsigned long *) seedBuffer);
  309.         for(j = 0; j < 16; j++)
  310.             randpool[i+j] ^= iv[j];
  311.         memcpy(iv, randpool+i, 16);
  312.     }
  313.  
  314.     /*
  315.         Now the somewhat dubious bit:  In order to make this fit in with
  316.         the existing code, we use the existing mechanism of keeping track
  317.         of a high-water mark in the buffer.  This is actually reasonably
  318.         realistic, since it keeps a count of what percentage of the full
  319.         buffer is random enough-- measuring the "molarity" of solution. 
  320.         However when it comes time to re-randomize the buffer in
  321.         randombyte(), it would probably be better to use the above
  322.         transformation than the existing randombyte() code.  I've left it 
  323.         as is to keep it as compatible as possible.
  324.     */
  325.  
  326.     abits += cbits;        /* Update count of bits of randomness */
  327.     while (abits >= 8)
  328.     {    /* We've got another byte's worth, increment the buffer pointer */
  329.         if (randcount < sizeof(randpool))
  330.             randcount++; /* not a byte counter-- now a molarity of randomness */
  331.         abits -= 8;
  332.     }
  333. #else    /* not USE_MD5 */
  334.     /* combine several sources to attempt maximum randomness... */
  335.     accum1 = keybuf;        /* actual keystroke */
  336.     accum1 += lastcounter;    /* add latched timer info */
  337.     accum1 += clock();        /* clock ticks */
  338.     accum1 += time(NULL);    /* seconds */
  339.  
  340.     accum1 ^= (accum1 >> cbits);    /* Fold upper and lower bits */
  341.  
  342.     /* slide some new bits into the bit accumulator: */
  343.     accum = (accum << cbits) | (unsigned int) (accum1 & cbitsmask);
  344.     abits += cbits;
  345.     while (abits >= 8)    /* another byte's worth of bits accumulated */
  346.     {    if (randcount < sizeof(randpool))
  347.             /* take lower byte of accum */
  348.             randpool[randcount++] = accum;
  349.         abits -= 8;
  350.         accum >>= 8;
  351.     }
  352. #endif /* not USE_MD5 */
  353. #undef cbitsmask
  354. }    /* capturecounter */
  355.  
  356.  
  357. /* Because these truly random bytes are so unwieldy to accumulate,
  358.    they can be regarded as a precious resource.  Unfortunately,
  359.    cryptographic key generation algorithms may require a great many
  360.    random bytes while searching about for large random prime numbers.
  361.    Fortunately, they need not all be truly random.  We only need as
  362.    many truly random bytes as there are bytes in the large prime we
  363.    are searching for.  These random bytes can be recycled and modified
  364.    via pseudorandom numbers until the key is generated, without losing
  365.    any of the integrity of randomness of the final key.
  366. */
  367.  
  368.  
  369. static void randstir(void)
  370. /* Stir up the recycled random number bin, via a pseudorandom generator */
  371. {    int i;
  372.     i = recyclecount;
  373.     while (i--)
  374.         recyclepool[i] ^= (byte) pseudorand();
  375.     DEBUGprintf2(" Stirring %d recycled bytes. ",recyclecount);
  376. }    /* randstir */
  377.  
  378.  
  379. short randload(short bitcount)
  380. /*    Flushes stale recycled random bits and copies a fresh supply of raw 
  381.     random bits from randpool to recyclepool.  Returns actual number of 
  382.     bits transferred.  Formerly named randrecycle. */
  383. {    int bytecount;
  384.     bytecount = (bitcount+7)/8;
  385.     bytecount = min(bytecount,randcount);
  386.     randflush();    /* reset recyclecount, discarding recyclepool */
  387.     while (bytecount--)
  388.         recyclepool[recyclecount++] = randpool[--randcount];
  389.     DEBUGprintf2("\nAllocating %d recycleable random bytes. ",recyclecount);
  390.     return(recyclecount*8);
  391. }    /* randload */
  392.  
  393.  
  394. void randflush(void)    /* destroys pool of recycled random numbers */
  395. /* Ensures no sensitive data remains in memory that can be recovered later. */
  396. {    recyclecount = sizeof (recyclepool);
  397.     while (recyclecount)
  398.         recyclepool[--recyclecount]=0;
  399.     /* recyclecount is left at 0 */
  400.     recycleptr = 0;
  401.     memset(seedBuffer, 0, 64);
  402.     memset(iv, 0, 16);
  403. }    /* randflush */
  404.  
  405.  
  406. short randombyte(void)
  407. /*    Returns truly random byte from pool, or a pseudorandom value
  408. **    if pool is empty.  It is recommended that the caller check
  409. **    the value of randcount before calling randombyte.
  410. */
  411. {    
  412.     /* First try to get a cheap recycled random byte, if there are any. */
  413.     if (recyclecount)    /* nonempty recycled pool */
  414.     {    if (++recycleptr >= recyclecount)    /* ran out? */
  415.         {    recycleptr = 0;    /* ran out of recycled random numbers */
  416.             randstir();    /* stir up recycled bits */
  417.         }
  418.         return (recyclepool[recycleptr]);
  419.     }
  420.  
  421.     /* Empty recycled pool.  Try a more expensive fresh random byte. */
  422.     if (randcount)    /* nonempty random pool--return a very random number */
  423.         return (randpool[--randcount]);
  424.  
  425.     /* Alas, fresh random pool is empty.  Get a pseudorandom byte.
  426.        Pseudorandom numbers are bad for cryptographic applications.
  427.        Although we will return a pseudorandom byte in the low order byte,
  428.        indicate error by making the result negative in the high byte.
  429.     */
  430.     /* DEBUGprintf1("\007Warning: random pool empty! "); */
  431.     return ( (pseudorand() & 0xFF) ^ (-1) );
  432. }    /* randombyte */
  433.  
  434.  
  435. boolean keypress(void)    /* TRUE iff keyboard input ready */
  436. {    /* Accumulates random numbers by timing user keystrokes. */
  437. #ifndef CRUDE
  438.     static short lastkey = 0; /* used to detect autorepeat key sequences */
  439.     static short next_to_lastkey = 0; /* allows a single repeated key */
  440.  
  441. #ifndef USEPCTIMER    /* no fast hardware timer available */
  442.     fastcounter++;    /* used in lieu of fast hardware timer counter */
  443. #endif    /* ifndef USEPCTIMER */
  444.  
  445.     if (keybuf & 0x100)    /* bit 8 means keybuf contains valid data */
  446.         return( TRUE );    /* key was hit the last time thru */
  447.  
  448.     if (kbhit() == 0)    /* keyboard was not hit */
  449.         return( FALSE );
  450.  
  451.     keybuf = getch() | 0x100; /* set data latch bit */
  452.  
  453.     /* Keyboard was hit.  Decide whether to call capturecounter... */
  454.  
  455.     /*  Guard against typahead buffer defeating fastcounter's randomness.
  456.     **  This could be a problem for multicharacter sequences generated
  457.     **  by a function key expansion or by the user generating keystrokes
  458.     **  faster than our event loop can handle them.  Only the last
  459.     **  character of a multicharacter sequence will trigger the counter
  460.     **  capture.  Also, don't let the keyboard's autorepeat feature
  461.     **  produce nonrandom counter capture.  However, we do allow a 
  462.     **  single repeated character to trigger counter capture, because
  463.     **  many english words have double letter combinations, and it's 
  464.     **  unlikely a typist would exploit the autorepeat feature to
  465.     **  type a simple double letter sequence.
  466.     **  We have some separate checks in capturecounter() to guard
  467.     **  against other reasons for characters coming in too fast.
  468.     */
  469.  
  470.     if (kbhit() == 0)    /* nothing in typahead buffer */
  471.     {    /* don't capture counter if key repeated */
  472.         if (keybuf != lastkey)
  473.             capturecounter(); /* read random noise from environment */
  474.         else if (keybuf != next_to_lastkey) /* allow single repeat */
  475.             capturecounter();
  476.         next_to_lastkey = lastkey;
  477.         lastkey = keybuf;
  478.     }
  479.     return( TRUE );
  480. #else    /* CRUDE */
  481.     return(FALSE);
  482. #endif
  483. }    /* keypress */
  484.  
  485.  
  486. short getkey(void)    /* Returns data from keyboard (no echo). */
  487. {    /* Also accumulates random numbers via keypress(). */
  488. #ifndef CRUDE
  489.     while(! keypress() );        /* loop until key is pressed. */
  490.     return( keybuf &= 0xff);    /* clear latch bit 8 */
  491. #else
  492.     return(keybuf = getch() & 0xff);
  493. #endif
  494. }    /* getkey */
  495.  
  496.  
  497. #define BS    8        /* ASCII backspace */
  498. #define CR    13        /* ASCII carriage return */
  499. #define LF    10        /* ASCII linefeed */
  500. #define DEL 0177    /* ASCII delete */
  501.  
  502. /* We will need a series of truly random bits for key generation.
  503.    In most implementations, our random number supply is derived from
  504.    random keyboard delays rather than a hardware random number
  505.    chip.  So we will have to ensure we have a large enough pool of
  506.    accumulated random numbers from the keyboard.  Later, randombyte
  507.    will return bytes one at a time from the accumulated pool of
  508.    random numbers.  For ergonomic reasons, we may want to prefill
  509.    this random pool all at once initially.  The randaccum function
  510.    prefills a pool of random bits.
  511. */
  512.  
  513. #if defined(UNIX) || defined(AMIGA) || defined(VMS)
  514. #define NEEDBREAK
  515. void ttycbreak();
  516. void ttynorm();
  517. #endif
  518.  
  519. #ifndef CRUDE    /* We can measure keyboard event times accurately. */
  520.  
  521. void randaccum(short bitcount)    /* Get this many random bits ready */
  522. {    short nbytes;
  523.     char c;
  524.     int col = 0;
  525.     unsigned long timer;
  526.     int fasts_rejected = 0;            /* number of too-fast keystrokes */
  527.  
  528.     nbytes = min((bitcount+7)/8,sizeof(randpool));
  529.     fasts_rejected = 0;    /* number of too-fast keystrokes */
  530.     toofast = 0;    /* clear too-fast latch */
  531.  
  532.     if (randcount < nbytes)    /* if we don't have enough already */
  533.     {    fprintf(stderr,PSTR("\nWe need to generate %d random bytes.  This is done by measuring the\
  534. \ntime intervals between your keystrokes.  Please enter some text on your\
  535. \nkeyboard, at least %d nonrepeating keystrokes, until you hear the beep:\n"),
  536.             nbytes-randcount, (8*(nbytes-randcount)+cbits-1)/cbits);
  537. #ifdef NEEDBREAK
  538.         ttycbreak();
  539. #endif
  540.         while (randcount < nbytes)
  541.         {    c=getkey();
  542.             if (toofast)
  543.             {    fasts_rejected++;    /* keep score */
  544.                 toofast = 0;        /* reset latch */
  545.                 putc('?', stderr);    /* indicate trouble */
  546.             }
  547.             else if ((nbytes - randcount) < 2)
  548.                 putc('O', stderr);
  549.             else if ((nbytes - randcount) < 4)
  550.                 putc('o', stderr);
  551.             else 
  552.                 putc('.', stderr);
  553.             /**
  554.             putc(c,stderr);
  555.             if (c==CR) fputc(LF,stderr);
  556.             **/
  557.             if (++col == 64)
  558.             {    putc('\n', stderr);
  559.                 col = 0;
  560.             }
  561.             fflush(stderr);
  562.         }
  563.         fprintf(stderr,PSTR("\007*\n-Enough, thank you.\n"));
  564.  
  565.         if (fasts_rejected > 2)    /* Did user type too fast? */
  566.             fprintf(stderr,PSTR("(Ignored %d keystrokes that were typed too fast.)\n"), 
  567.                 fasts_rejected);
  568.  
  569.         /* Clean up typeahead for at least 1 full second... */
  570.         timer = time(NULL) + 1;    /* need at least 1 second of quiet */
  571.         while ((unsigned long) time(NULL) <= timer)
  572.         {    if (keypress())    /* user touched a key, reset timer */
  573.             {    getkey();
  574.                 timer = time(NULL) + 1;
  575.             }
  576.         }
  577.  
  578. #ifdef NEEDBREAK
  579.         ttynorm();
  580. #endif /* !NEEDBREAK */
  581.     }
  582. }    /* randaccum */
  583.  
  584. #endif    /* not CRUDE */
  585.  
  586.  
  587. #ifdef CRUDE    /* We cannot measure keyboard event times accurately. */
  588.  
  589. /*    This is a really lousy way to make random numbers.  We will only use
  590.     this method as a last resort, only if this machine does not allow
  591.     keyboard events to be timed accurately.  It's better than nothing.
  592.     The other randaccum function listed above is much better, if the
  593.     CRUDE symbol is undefined and the environment will support it.
  594.  
  595.     We could improve this scheme somewhat by using a good hashing
  596.     function such as MD4 or MD5 on the user input before capturing it 
  597.     in the random pool.
  598. */
  599.  
  600. void randaccum(short bitcount)    /* Get this many random bits ready */
  601. {    short nbytes;
  602.     char c, flushbuf[80];
  603.     nbytes = min((bitcount+7)/8,sizeof(randpool));
  604.  
  605.     randcount = 0;    /* start with nothing in pool. */
  606.     capturemode = TRUE;    /* enable capture of random keys */
  607.     fastcounter += time(0);    /* start with time of day, if available */
  608.  
  609.     fprintf(stderr,PSTR("\nWe need to generate %d random bytes.\
  610. \nPlease enter at least %d random keystrokes, as random\
  611. \nas you can possibly make them.\n"),
  612.         nbytes-randcount, (8*(nbytes-randcount)+cbits-1)/cbits);
  613.     while (randcount < nbytes)
  614.     {    c=getkey();
  615.         capturecounter();
  616.     }
  617.     /*
  618.      * CRUDE mode must work in normal tty mode, so we can't
  619.      * use keypress() to flush input.
  620.      */
  621. #ifdef AMIGA
  622.     while(keypress()) getch();
  623. #else
  624.     fgets(flushbuf, sizeof(flushbuf), stdin);
  625. #endif
  626.     fprintf(stderr,PSTR("\007 -Enough, thank you.\n"));
  627.  
  628.     capturemode = FALSE;    /* don't capture any more keys */
  629.  
  630. #ifdef NEEDBREAK
  631.     ttynorm();
  632. #endif
  633. }    /* randaccum */
  634.  
  635. #endif    /* CRUDE */
  636.  
  637.  
  638. int getstring(char *strbuf, int maxlen, boolean echo)
  639. /*    Gets string from user, with no control characters allowed.
  640.     Also accumulates random numbers by calling getkey().
  641.     maxlen is max length allowed for string.
  642.     echo is TRUE iff we should echo keyboard to screen.
  643.     Returns null-terminated string in strbuf.
  644. */
  645. {    short i;
  646.     char c;
  647. #ifdef NEEDBREAK
  648.     ttycbreak();
  649. #endif
  650. #ifdef AMIGA
  651.     aecho = (int)echo;
  652.     echo = FALSE;   /* echo is done in getch */
  653. #endif  /* AMIGA */
  654.     fflush(stdout);
  655.     i=0;
  656.     while (TRUE)
  657.     {    fflush(stderr);
  658.         c = getkey();
  659.         if (c==BS || c==DEL)
  660.         {    if (i)
  661.             {    if (echo)
  662.                 {    fputc(BS,stderr);
  663.                     fputc(' ',stderr);
  664.                     fputc(BS,stderr);
  665.                 }
  666.                 i--;
  667.             }
  668.             continue;
  669.         }
  670.         if (c < ' ' && c != LF && c != CR)
  671.         {    putc('\007', stderr);
  672.             continue;
  673.         }
  674.         if (echo) fputc(c,stderr);
  675.         if (c==CR)
  676.         {    if (echo) fputc(LF,stderr);
  677.             break;
  678.         }
  679.         if (c==LF)
  680.             break;
  681.         if (c=='\n')
  682.             break;
  683.         strbuf[i++] = c;
  684.         if (i>=maxlen)
  685.         {    fprintf(stderr,"\007*\n");    /* -Enough! */
  686.             while (keypress())
  687.                 getkey();    /* clean up any typeahead */
  688.             break;
  689.         }
  690.     }
  691.     strbuf[i] = '\0';    /* null termination of string */
  692. #ifdef NEEDBREAK
  693.     ttynorm();
  694. #endif
  695.     return(i);        /* returns string length */
  696. }    /* getstring */
  697.  
  698.  
  699. #endif            /* ifndef PSEUDORANDOM */
  700.  
  701. void flush_input()
  702. {
  703. #ifdef NEEDBREAK
  704.     ttycbreak();
  705. #endif
  706.     while (keypress())    /* flush typahead buffer */
  707.         getkey();
  708. #ifdef NEEDBREAK
  709.     ttynorm();
  710. #endif
  711. }
  712.  
  713.